import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;

import java.util.Arrays;
import java.util.Scanner;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 沈明月
 * Date: 2022-11-02
 * Time: 20:46
 */
public class KnowledgeTwo {
//数组：
    public static void main1(String[] args){
//数组的定义与使用：
        int [] array = {1,2,3,4,5};
        //[]里面不能放东西
        //int []--->类型
        //只要写了{}，就不能在[]放数据

//创建数组的三种方式：
        int [] array1 = {1,2,3,4,5};
        int [] array2 = new int[]{1,2,3,4,5,6};
        //上面两种是静态初始化，根据元素的个数来确定数组的长度

        int [] array3 = new int [10];//只分配了空内存，没有放东西，默认是0
        //array3这种初始化是动态初始化

        //int arr[]={1,2,3};--->这种语句不会报错，但是不符合Java的语法
        int [] array4;

//拆分初始化：
        //静态初始化：
        int[] arr1;
        arr1 = new int[]{1,2,3};//此处的new int 不能省略

        //动态初始化：
        int [] arr2;
        arr2 = new int []{1,2,3,4};

        int [] array6 = {1,21,3,43,5,6};
//求数组长度：
        System.out.println(array6.length);

//打印数组内的元素：
        System.out.println(array6[0]);
        System.out.println(array6[1]);
//遍历数组：
        //法一：
        for (int i = 0; i < array6.length; i++) {
            System.out.print(array6[i]+" ");
        }
        System.out.println();
        //法二：for-each
        //数组中的元素的类型 数字中每个元素的类型定义的变量：数组类型
        //for(int          x                     :   array)
        for (int x : array6){
            System.out.print(x+" ");
        }
        System.out.println();
        //法三：
        Arrays.sort(array6);//对数组排序
        String ret = Arrays.toString(array6);
        System.out.println(ret);//--->把数组转变成字符串的形式输出
    }


    public static void main2(String[] args) {
        //引用变量其实就是一个变量，存放地址的
        //局部变量的内存在栈上开辟的，是在方法内部定义的变量
        //基本数据类型：byte,short,int,float,long,double,boolean,char

        //Java中，局部变量在使用的时候必须初始化
     /* int [] Array;
        System.out.println(Array);*/
        int [] array = null;//这意味着array这个引用不指向任何对象
        System.out.println(Arrays.toString(array));
        int a = 0;
        System.out.println(a);
    }


    public static void main3(String[] args) {
        int[] array1 = {1,2,3,4};
        array1[0] = 99;

        int[] array2 = array1;
        //把array1的值赋给array2,其实就是把1,2,3,4的地址给了array2
        //代表array2这个引用指向了array1这个引用所指向的对象

        array2[0] = 100;
        //这里把100赋给array2[0]也就是把100赋给array1[0];
        //因为地址一样

        System.out.println(Arrays.toString(array1));//[100, 2, 3, 4]
        System.out.println(Arrays.toString(array2));//[100, 2, 3, 4]

        //例子2：
        int[] array3 = {1,2,3,4};
        int[] array4 = {11,22,33,44};

        array3 = array4;
        array3[0] = 1888;

        System.out.println(Arrays.toString(array3));//[1888, 22, 33, 44]
        System.out.println(Arrays.toString(array4));//[1888, 22, 33, 44]
        //此时，因为没有变量引用{1，2，3，4}的地址了，所以他会被回收
        //当两个引用指向同一个对象的时候，通过任何一个引用去修改这个对象的值，另一个引用访问这个对象的时候，它也是会发生改变的
    }


//数组为参数传递：
//只是改变了形参的指向，并没有改变实参的指向
    public static void func1(int[] array){
        //在array刚拿到的时候，他里面存放的还是实参里面的内容，指向的对象和实参所指向的对象是一样的
        //但是当他new 以后，这意味着它指向了一个新的对象，存放了一个新的地址
        array = new int[]{15,16,17};
    }
//此时传递的是引用，通过此引用我们可以修改对象的值
    public static void func2(int[] array){
        //在array刚拿到的时候，他里面存放的是实参里面的内容，指向的对象和实参所指向的对象是一样的
        //此时array并没有new一个新的引用，而是通过0下标把引用的对象里面的第一个元素进行了修改
        array[0] = 999;
    }
    public static void main4(String[] args) {
        int[] array = {1,2,3};
        /*func1(array);
        System.out.println(Arrays.toString(array));//[1,2,3](屏蔽func2时）*/
        func2(array);
        System.out.println(Arrays.toString(array));//[999, 2, 3](屏蔽func1时）
    }
//当数组作为参数传递的时候，其实还是按值传递，只不过传递的值是一个地址
//那么就会出现两种情况：
//形参改变指向： array = new int[];
//形参修改指向对象的值：array[0] = 9--->此时才会影响到实参


//数组作为返回值进行传递：
    public static int[] func3(){
        int[] tmpArr = {10,11,13,12};
        return tmpArr;
    }
//将数组扩大两倍：
    public static int[] grow1(int[] array){
        //法一：相当于在同一个对象上扩大两倍，所以可以考虑不用返回
        for (int i = 0; i < array.length; i++) {
            array[i] = array[i]*2;
        }
        return array;
    }
    //修改：
    public static void grow2(int[] array) {
        for (int i = 0; i < array.length; i++) {
            array[i] = array[i] * 2;
        }
    }

//法二：在一个新的数组里进行扩大，再返回这个接收了扩大后的元素的数组
    public static int[] grow3(int[] array){
        int [] tmpArray = new int[array.length];
        for (int i = 0; i < array.length; i++) {
            tmpArray[i] = array[i]*2;
        }
        return tmpArray;
    }
    public static void main5(String[] args) {
        int[] array = {1,2,3,4};

        int[] array1 = func3();
        System.out.println(Arrays.toString(array1));//[10, 11, 13, 12]
//将数组扩大两倍：
        int[] array2 = grow1(array);
        System.out.println(Arrays.toString(array2));//[2, 4, 6, 8]
    }


//将数组以字符串的形式输出：
    public static String mytoString(int[] array){
        //一拿到数组一定要先判断是否是空指针：
        if(array == null){
            return "null";
        }
        //不停地拼接：
        String ret ="[";
        for (int i = 0; i < array.length; i++) {
            ret +=array[i];
            if(i != array.length-1){
                ret +=",";
            }
        }
        ret = ret +"]";
        return ret;
    }
    public static void main6(String[] args) {
        int[] array = {1,2,3,4};
        System.out.println(mytoString(array));//[1,2,3,4,]
    }


//数组拷贝：
    public static void main7(String[] args) {
        int[] array1 = {1,2,3,4};
        System.out.println(Arrays.toString(array1));
        int[] array2 = array1;
        //这种情况算不得拷贝，只是把array1里面的值给了array2
        //而且它只有一个数组对象
        System.out.println(Arrays.toString(array2));

//真正的拷贝：
        //方法一：
        int[] array3 = {11,22,33,44};
        int[] array4 = new int[array3.length];
        for (int i = 0; i < array3.length; i++) {
            array4[i] = array3[i];
        }
        System.out.println("=====================");
//拷贝成功以后，如果改变array4里面的值，并不会影响array3所引用的对象：
        array4[0] = 199;
        System.out.println(Arrays.toString(array3));//[11, 22, 33, 44]
        System.out.println(Arrays.toString(array4));//[199, 22, 33, 44]
        //因为他们已经是两个变量了
        System.out.println("=====================");
//Java内部有的拷贝方法：
        int[] array5 = {12,23,43};
        //接收返回值     = Arrays.copyOf（被拷贝的数组，被拷贝的长度）
        int[] array6 = Arrays.copyOf(array5,array5.length);
        //对数组大小进行扩容：
        int[] array7 = Arrays.copyOf(array5,array5.length*2);
        System.out.println(Arrays.toString(array6));//[12, 23, 43]
        System.out.println("=====================");
//.clone克隆：
        int[] arr4 = {1,2,3,4};
        int[] arr5 = arr4.clone();//克隆就是产生一个副本
        System.out.println(Arrays.toString(arr4));
        System.out.println(Arrays.toString(arr5));
        System.out.println("=====================");
//指定区间的拷贝：
        //public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
        //src--->从哪里拷贝
        //srcPos--->从拷贝数组的哪个位置开始拷贝
        //dest--->拷贝到哪里
        //destPos--->拷贝到数组的哪个位置
        //length--->拷贝多长(当拷贝的元素个数超出了dest的总元素个数的时候，会报错）
        int[] array8 = new int[array5.length];
        System.arraycopy(array5,0,array8,0,array5.length);
        System.out.println("=====================");
//拷贝范围：
        int[] array9 = {78,5,43,34};
        int[] array10 = Arrays.copyOfRange(array9,1,3);//from,to是左闭右开区间【，）
        System.out.println(Arrays.toString(array10));//[5, 43]
        System.out.println("=====================");
//Arrays.equals():判断两个数组是否相等:
        int[] arr1 = {1,2,3,4};
        int[] arr2 = {1,2,3,4};
        System.out.println(arr1 == arr2);
        //false
        //因为arr1和arr2里面存放的都是地址，虽然他们所引用的对象的内容是一样的，但并不意味着地址一样
        System.out.println("=====================");
        System.out.println(Arrays.equals(arr1,arr2));//true
        System.out.println("=====================");
//Arrays.fill():把一个数组里所有的元素都赋值成讨同一个数：
        int[] arr3 = new int[10];
       /* Arrays.fill(arr3,9);
        System.out.println(Arrays.toString(arr3));//[9, 9, 9, 9, 9, 9, 9, 9, 9, 9]*/
        System.out.println("=====================");
        //加范围版：
        Arrays.fill(arr3,1,4,9);
        System.out.println(Arrays.toString(arr3));//[0, 9, 9, 9, 0, 0, 0, 0, 0, 0]（屏蔽前面的无范围的赋值所得）
        System.out.println("=====================");
//Arrays.里面用得较多的方法：sort(),toString(),fill(),copyOf()
    }


//深浅拷贝的区别：

//被考备的数组：arr1
//待考备的对象：arr2
//浅拷贝：如果改变了arr2数组里面的内容，arr1会受到影响，这样的拷贝叫做浅拷贝
//深拷贝：如果改变arr2数组里面的内容，arr1不会受到影响，这样的拷贝叫做深拷贝


//查找数组中指定的元素：
//法一：简单粗暴，一个一个看
    public static int find1(int[] array, int val){
        for (int i = 0; i < array.length; i++) {
            if(array[i] == val){
                return i;
            }
        }
        return -1;
    }
//法二：二分查找法（折半查找法）
    public static int find2(int[] array, int val){
        //先排序：
        Arrays.sort(array);
        int left = 0;
        int right = array.length-1;
        while(left <= right){
            int mid = (left+right)/2;
            if(array[mid] == val){
                return mid;
            }else if(array[mid] > val){
                right = mid -1;
            }else if(array[mid] < val){
                left = mid+1;
            }
        }
        return -1;
    }
    public static void main8(String[] args) {
        int[] array = {1,2,3,4,5};
        int ret = find1(array, 4);
        System.out.println(ret);
    }


//创建的数组，并且赋初始值:创建一个 int 类型的数组, 元素个数为 100, 并把每个元素依次设置为 1 - 100
    public static void main9(String[] args) {
        int [] array = new int [100];
        for (int i = 0; i < 100; i++) {
            array[i] = i+1;
        }
        System.out.println(Arrays.toString(array));//null
        for (int x : array){
            System.out.print(x+" ");
        }
    }


    //二维数组：
    //数组逆序输出：
    public static void reverse(int[] array){
        int left = 0;
        int right = array.length-1;
        while(left < right){
            int tmp = array[left];
            array[left] = array [right];
            array[right] = tmp;
            left++;
            right--;
        }
        System.out.println(Arrays.toString(array));
    }
    public static void main10(String[] args) {
        int[] array = new int []{1,2,3,4};
        reverse(array);
    }

    public static void main11(String[] args) {
        int[][] array = {{1,2,3},{11,2,3}};
        //对二维数组初始化的三种方式：
        int [][] array1 = new int [][]{{1,2,3,4},{5,6,7,8}};
        int [][] array2 = {{1,2,3},{1,2,3}};
        int[][] array3 = new int[2][3];
//完美体现二维数组是一个特殊的一维数组
        System.out.println(Arrays.toString(array[0]));//输出第一行
        System.out.println(Arrays.toString(array[1]));//输出第二行
//通过for循环遍历：
        for (int i = 0; i < array.length; i++) {//array.length表示二维数组有几行
            for (int j = 0; j < array[i].length; j++) {//array[i].length表示第i行的元素个数
                System.out.print(array[i][j]+" ");//打印第i行第j列所表示的元素
            }
            System.out.println();
        }
//通过for-each遍历：
        //for(数组里面的每一个元素：数组名称）
        for (int[] ret:array) {//array是一个二维数组，它有两个元素，每个都是一个一维数组
            for (int x:ret){
                System.out.print(x+" ");
            }
            System.out.println();
        }
//打印二维数组：
        System.out.println(Arrays.deepToString(array));

        System.out.println("===========");
        //在Java中行不能省略
        int [][] array4 = new int [2][];
        System.out.println(array[0]);//null
        System.out.println(array[1]);//null
        //不规则数组：每一行的长度不一样
        array4[0]=new int [2];
        array4[1] = new int [4];
    }
    public static void main12(String[] args) {
        int[][] array3 = new int[2][3];//行不能省略，列可以省略
        //当没有列的时候输出null：
        int[][] array2 = new int [2][];
        System.out.println(array2[0]);//null
        System.out.println(array2[1]);//null
        //二维数组中每一行的元素个数可以不同：（此类数组称为不规则数组）
        array2[0] = new int[2];//二维数组第一行有2个元素
        array2[1] = new int[3];//二维数组第二行有3个元素
        System.out.println(Arrays.toString(array2[0]));//[0, 0]
        System.out.println(Arrays.toString(array2[1]));//[0, 0, 0]
    }
}
